package ru.volgogradetzzz.math {
	import ru.volgogradetzzz.math.VMatrix3x3;
	import ru.volgogradetzzz.math.VVector3;
	
	/**
	 * ...
	 * @author volgogradetzzz
	 */
	public class VMatrix4x4 {
		
		public var m11:Number, m12:Number, m13:Number, m14:Number;
		public var m21:Number, m22:Number, m23:Number, m24:Number;
		public var m31:Number, m32:Number, m33:Number, m34:Number;
		public var m41:Number, m42:Number, m43:Number, m44:Number;
		
		public function VMatrix4x4(	m11:Number = 1, m12:Number = 0, m13:Number = 0, m14:Number = 0,
									m21:Number = 0, m22:Number = 1, m23:Number = 0, m24:Number = 0,
									m31:Number = 0, m32:Number = 0, m33:Number = 1, m34:Number = 0,
									m41:Number = 0, m42:Number = 0, m43:Number = 0, m44:Number = 1) 
		{
			this.m11 = m11; this.m12 = m12; this.m13 = m13; this.m14 = m14;
			this.m21 = m21; this.m22 = m22; this.m23 = m23; this.m24 = m24;
			this.m31 = m31; this.m32 = m32; this.m33 = m33; this.m34 = m34;
			this.m41 = m41; this.m42 = m42; this.m43 = m43; this.m44 = m44;
		}
		
		public function identity():void {
			m11 = 1; m12 = 0; m13 = 0; m14 = 0;
			m21 = 0; m22 = 1; m23 = 0; m24 = 0;
			m31 = 0; m32 = 0; m33 = 1; m34 = 0;
			m41 = 0; m42 = 0; m43 = 0; m44 = 1;
		}
		
		public function transpose():void {
			var temp12:Number = m12;
			var temp13:Number = m13;
			var temp14:Number = m14;
			var temp23:Number = m23;
			var temp24:Number = m24;
			var temp34:Number = m34;
			
			m12 = m21;
			m21 = temp12;
			m13 = m31;
			m31 = temp13;
			m23 = m32;
			m32 = temp23;
			m14 = m41;
			m41 = temp14;
			m24 = m42;
			m42 = temp24;
			m34 = m43;
			m43 = temp34;
		}
		
		public function multiplyByVector(v:VVector3):void {
			var vx:Number = v.x;
			var vy:Number = v.y;
			var vz:Number = v.z;
			var vw:Number = v.w;
			
			v.x = m11 * vx + m12 * vy + m13 * vz + m14 * vw;
			v.y = m21 * vx + m22 * vy + m23 * vz + m24 * vw;
			v.z = m31 * vx + m32 * vy + m33 * vz + m34 * vw;
			v.w = m41 * vx + m42 * vy + m43 * vz + m44 * vw;
		}
		
		public function multiplyByMatrix(m:VMatrix4x4):void {
			var temp11:Number = m11 * m.m11 + m12 * m.m21 + m13 * m.m31 + m14 * m.m41;
			var temp12:Number = m11 * m.m12 + m12 * m.m22 + m13 * m.m32 + m14 * m.m42;
			var temp13:Number = m11 * m.m13 + m12 * m.m23 + m13 * m.m33 + m14 * m.m43;
			var temp14:Number = m11 * m.m14 + m12 * m.m24 + m13 * m.m34 + m14 * m.m44;
			
			var temp21:Number = m21 * m.m11 + m22 * m.m21 + m23 * m.m31 + m24 * m.m41;
			var temp22:Number = m21 * m.m12 + m22 * m.m22 + m23 * m.m32 + m24 * m.m42;
			var temp23:Number = m21 * m.m13 + m22 * m.m23 + m23 * m.m33 + m24 * m.m43;
			var temp24:Number = m21 * m.m14 + m22 * m.m24 + m23 * m.m34 + m24 * m.m44;
			
			var temp31:Number = m31 * m.m11 + m32 * m.m21 + m33 * m.m31 + m34 * m.m41;
			var temp32:Number = m31 * m.m12 + m32 * m.m22 + m33 * m.m32 + m34 * m.m42;
			var temp33:Number = m31 * m.m13 + m32 * m.m23 + m33 * m.m33 + m34 * m.m43;
			var temp34:Number = m31 * m.m14 + m32 * m.m24 + m33 * m.m34 + m34 * m.m44;
			
			var temp41:Number = m41 * m.m11 + m42 * m.m21 + m43 * m.m31 + m44 * m.m41;
			var temp42:Number = m41 * m.m12 + m42 * m.m22 + m43 * m.m32 + m44 * m.m42;
			var temp43:Number = m41 * m.m13 + m42 * m.m23 + m43 * m.m33 + m44 * m.m43;
			var temp44:Number = m41 * m.m14 + m42 * m.m24 + m43 * m.m34 + m44 * m.m44;
			
			m11 = temp11; m12 = temp12; m13 = temp13; m14 = temp14;
			m21 = temp21; m22 = temp22; m23 = temp23; m24 = temp24;
			m31 = temp31; m32 = temp32; m33 = temp33; m34 = temp34;
			m41 = temp41; m42 = temp42; m43 = temp43; m44 = temp44;
		}
		
		public function setupRotation(angX:Number, angY:Number, angZ:Number):void {
			var sinX:Number = Math.sin(angX);
			var cosX:Number = Math.cos(angX);
			
			var sinY:Number = Math.sin(angY);
			var cosY:Number = Math.cos(angY);
			
			var sinZ:Number = Math.sin(angZ);
			var cosZ:Number = Math.cos(angZ);
			
			m11 = cosY * cosZ + sinY * sinX * sinZ;		m12 = sinZ * cosX;	m13 = -sinY * cosZ + cosY * sinX * sinZ;	m14 = 0;
			m21 = -cosY * sinZ + sinY * sinX * cosZ;	m22 = cosZ * cosX;	m23 = sinZ * sinY + cosY * sinX * cosZ;		m24 = 0;
			m31 = sinY * cosX;							m32 = -sinX;		m33 = cosY * cosX;							m34 = 0;
			m41 = 0;									m42 = 0;			m43 = 0;									m44 = 1;
		}
		
		public function setupTranslation(tx:Number = 0, ty:Number = 0, tz:Number = 0):void {
			m11 = 1;	m12 = 0;	m13 = 0;	m14 = 0;
			m21 = 0;	m22 = 1;	m23 = 0;	m24 = 0;
			m31 = 0;	m32 = 0;	m33 = 1;	m34 = 0;
			m41 = tx;	m42 = ty;	m43 = tz;	m44 = 1;
		}
		
		public function setupScale(sx:Number = 1, sy:Number = 1, sz:Number = 1):void {
			m11 = sx;
			m22 = sy;
			m33 = sz;
			
			m11 = sx;	m12 = 0;	m13 = 0;	m14 = 0;
			m21 = 0;	m22 = sy;	m23 = 0;	m24 = 0;
			m31 = 0;	m32 = 0;	m33 = sz;	m34 = 0;
			m41 = 0;	m42 = 0;	m43 = 0;	m44 = 1;
		}
		
		public function setupPerspectiveFOV(fov:Number, ratio:Number, n:Number, f:Number):void {
			var s:Number = 1 / Math.tan(fov * 0.5);
			
			m11 = s / ratio;	m12 = 0;	m13 = 0;					m14 = 0;
			m21 = 0; 			m22 = s;	m23 = 0;					m24 = 0;
			m31 = 0;			m32 = 0;	m33 = f / (f - n);			m34 = 1;
			m41 = 0;			m42 = 0;	m43 = -f * n / (f - n);		m44 = 0;
		}
		
		public function setupOrthogonal(l:Number, r:Number, t:Number, b:Number, n:Number, f:Number):void {
			m11 = 2 / (r - l);			m12 = 0;					m13 = 0;			m14 = 0;
			m21 = 0;					m22 = 2 / (t - b);			m23 = 0;			m24 = 0;
			m31 = 0;					m32 = 0;					m33 = 1 / (f - n);	m34 = 0;
			m41 = (l + r) / (l - r);	m42 = (t + b) / (b - t);	m43 = n / (n - f);	m44 = 1;
		}
		
		public function copyFrom(m:VMatrix4x4):void {
			m11 = m.m11; m12 = m.m12; m13 = m.m13; m14 = m.m14;
			m21 = m.m21; m22 = m.m22; m23 = m.m23; m24 = m.m24;
			m31 = m.m31; m32 = m.m32; m33 = m.m33; m34 = m.m34;
			m41 = m.m41; m42 = m.m42; m43 = m.m43; m44 = m.m44;
		}
		
		public function toString():String {
			return 	'[' + m11 + ', ' + m12 + ', ' + m13 + ', ' + m14 + ',\n' +
					' ' + m21 + ', ' + m22 + ', ' + m23 + ', ' + m24 + ',\n' +
					' ' + m31 + ', ' + m32 + ', ' + m33 + ', ' + m34 + ',\n' +
					' ' + m41 + ', ' + m42 + ', ' + m43 + ', ' + m44 + ']';
		}
	}
}